#include "BigInteger.h"

BigInteger::BigInteger() : num("0"), isNegative(false) {}

BigInteger::BigInteger(const std::string& str) {
    if (str.empty()) {
        num = "0";
        isNegative = false;
        return;
    }

    size_t start = 0;
    if (str[0] == '-') {
        isNegative = true;
        start = 1;
    } else if (str[0] == '+') {
        isNegative = false;
        start = 1;
    } else {
        isNegative = false;
    }

    num = str.substr(start);
    removeLeadingZeros();
    if (num == "0") {
        isNegative = false;
    }
}

BigInteger::BigInteger(long long val) {
    if (val < 0) {
        isNegative = true;
        val = -val;
    } else {
        isNegative = false;
    }
    num = std::to_string(val);
}

void BigInteger::removeLeadingZeros() {
    size_t start = 0;
    while (start < num.size() - 1 && num[start] == '0') {
        start++;
    }
    num = num.substr(start);
}

int BigInteger::compareAbs(const BigInteger& other) const {
    if (num.size() > other.num.size()) {
        return 1;
    } else if (num.size() < other.num.size()) {
        return -1;
    } else {
        return num.compare(other.num);
    }
}

BigInteger BigInteger::operator+(const BigInteger& other) const {
    // 同号相加
    if (isNegative == other.isNegative) {
        std::string result;
        int carry = 0;
        int i = num.size() - 1;
        int j = other.num.size() - 1;

        while (i >= 0 || j >= 0 || carry > 0) {
            int sum = carry;
            if (i >= 0) sum += num[i--] - '0';
            if (j >= 0) sum += other.num[j--] - '0';
            carry = sum / 10;
            result = std::to_string(sum % 10) + result;
        }

        BigInteger res(result);
        res.isNegative = isNegative;
        return res;
    } else {
        // 异号相加，转化为减法
        if (compareAbs(other) >= 0) {
            BigInteger temp = *this;
            temp.isNegative = false;
            BigInteger sub = temp - other;
            sub.isNegative = isNegative;
            return sub;
        } else {
            BigInteger temp = other;
            temp.isNegative = false;
            BigInteger sub = temp - *this;
            sub.isNegative = other.isNegative;
            return sub;
        }
    }
}

BigInteger BigInteger::operator-(const BigInteger& other) const {
    // 转化为加上相反数
    BigInteger negOther = other;
    negOther.isNegative = !negOther.isNegative;
    return *this + negOther;
}

BigInteger BigInteger::operator*(const BigInteger& other) const {
    if (num == "0" || other.num == "0") {
        return BigInteger("0");
    }

    std::string result(num.size() + other.num.size(), '0');

    for (int i = num.size() - 1; i >= 0; i--) {
        int carry = 0;
        for (int j = other.num.size() - 1; j >= 0; j--) {
            int mul = (num[i] - '0') * (other.num[j] - '0') + (result[i + j + 1] - '0') + carry;
            carry = mul / 10;
            result[i + j + 1] = (mul % 10) + '0';
        }
        result[i] += carry;
    }

    BigInteger res(result);
    res.isNegative = isNegative != other.isNegative;
    res.removeLeadingZeros();
    if (res.num == "0") {
        res.isNegative = false;
    }
    return res;
}

BigInteger BigInteger::operator/(const BigInteger& other) const {
    if (other.num == "0") {
        throw std::invalid_argument("Division by zero");
    }
    if (compareAbs(other) < 0) {
        return BigInteger("0");
    }
    if (num == other.num) {
        return BigInteger(isNegative != other.isNegative ? "-1" : "1");
    }

    BigInteger dividend = *this;
    dividend.isNegative = false;
    BigInteger divisor = other;
    divisor.isNegative = false;

    std::string result;
    BigInteger temp;

    for (size_t i = 0; i < dividend.num.size(); i++) {
        temp.num += dividend.num[i];
        temp.removeLeadingZeros();

        int count = 0;
        while (temp.compareAbs(divisor) >= 0) {
            temp = temp - divisor;
            count++;
        }

        result += std::to_string(count);
    }

    BigInteger res(result);
    res.removeLeadingZeros();
    res.isNegative = isNegative != other.isNegative;
    return res;
}

std::ostream& operator<<(std::ostream& os, const BigInteger& bigInt) {
    if (bigInt.isNegative && bigInt.num != "0") {
        os << "-";
    }
    os << bigInt.num;
    return os;
}

std::istream& operator>>(std::istream& is, BigInteger& bigInt) {
    std::string str;
    is >> str;
    bigInt = BigInteger(str);
    return is;
}
